#include "HiredisClient.h"

#include <hiredis/hiredis.h>
#include <iostream>
#include <memory>

#define GLOG_USE_GLOG_EXPORT
#include <glog/logging.h>

HiredisClient::HiredisClient(const std::string &ip, uint16_t port) : m_ipaddr(ip), m_port(port), m_connected(false)
{
    m_context = nullptr;
}

HiredisClient::~HiredisClient()
{
    if (m_context) {
        redisFree(m_context);
    }
}

bool HiredisClient::connect()
{
    if (m_connected) {
        m_context = redisConnect(m_ipaddr.c_str(), m_port);
        if (!m_context || m_context->err) {
            if (m_context) {
                LOG(INFO) << "Connection error: " << m_context->errstr;
                redisFree(m_context);
            } else {
                std::cout << "Connection error: can't allocate redis context" << std::endl;
            }
            return false;
        }
    }

    m_connected = true;
    return true;
}

bool HiredisClient::execute(const char *command, ...)
{
    if (!connect())
        return false;

    redisReply *reply;
    va_list     args;
    va_start(args, command);
    redisvAppendCommand(m_context, command, args);
    va_end(args);
    return true;
}

std::shared_ptr<redisReply> HiredisClient::getReply()
{
    redisReply *reply;
    if (redisGetReply(m_context, reinterpret_cast<void **>(&reply)) != REDIS_OK) {
        std::cout << "redisGetReply error!" << std::endl;
        redisFree(m_context);
        m_connected = false;
        return nullptr;
    }

    return std::shared_ptr<redisReply>(reply, [](redisReply *reply) {
        freeReplyObject(reply);
    });
}